package pub.cleangao.memm.registry;

import pub.cleangao.memm.transport.RequestTransport;
import pub.cleangao.memm.transport.netty.NettyRpcClient;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;


public class RpcRuntime {


    private static RequestTransport nettyRpcClient;
    private static RpcConfigProperties configProperties;
    private static RpcServiceRegistry registry;

    private static final Map<String, Class<?>> fallbacks = new HashMap<>();


    public static RpcServiceRegistry getRegistry() {
        if (registry == null) {
            registry = EtcdServiceRegistry.getInstance();
        }
        return registry;
    }


    public static RequestTransport getRequestClient() {
        if (nettyRpcClient == null) {
            nettyRpcClient = NettyRpcClient.getInstance();
        }
        return nettyRpcClient;
    }


    public static void setRequestClient(RequestTransport nettyRpcClient) {
        RpcRuntime.nettyRpcClient = nettyRpcClient;
    }

    public static RpcConfigProperties getConfigProperties() {
        if (configProperties == null) {
            configProperties = RpcConfigProperties.init();
        }
        return configProperties;
    }

    public static void downShelf() {
        getRegistry().unregister();
        getRequestClient().shutdown();
    }

    public static void addUnHealthServeNode(String host, int port) {
        getRegistry().markUnHealth(host + ":" + port);
    }

    public static boolean testConnection(String hostPort) {
        RequestTransport client = getRequestClient();
        String[] hostAndPort = hostPort.split(":");
        return client.testConnection(hostAndPort[0], Integer.parseInt(hostAndPort[1]));
    }


    public static Object invokeFallback(String rpcServiceName, String methodName, Class<?>[] paramTypes, Object[] parameters) {
        Class<?> clazz = getFallbackClass(rpcServiceName);
        if (clazz == null) {
            return null;
        }
        try {
            Object target = clazz.getDeclaredConstructor().newInstance();
            Method method = clazz.getMethod(methodName, paramTypes);
            return method.invoke(target, parameters);
        } catch (Exception ignore) {
            return null;
        }
    }

    public static void setFallbacks(String rpcServiceName, Class<?> fallback) {
        fallbacks.put(rpcServiceName, fallback);
    }

    private static Class<?> getFallbackClass(String rpcServiceName) {
        return fallbacks.get(rpcServiceName);
    }


}
